/****************************************************************************
**
** Copyright (C) 2011 Jesús Martínez Pérez
**
** This program is free software: you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the 
** Free Software Foundation, either version 3 of the License, or (at your
** option) any later version.
**
** This program is distributed in the hope that it will be useful, but 
** WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
** or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
** for more details.
**
** You should have received a copy of the GNU General Public License along 
** with this program. If not, see <http://www.gnu.org/licenses/>
**
****************************************************************************/
#include <lz77.h>


LZ77::LZ77(){
}


LZ77::LZ77(VD_unsignedchar c,VD_unsignedint i){
	vi=i;
	vc=c;
}


void LZ77::Codifica(){
	int discont,loncont;
	vi.Add(vc.Get(0));
	vi.Add(vc.Get(1));
	for(int i=2;i<vc.Size();i++){
		for(int j=i-1;(i<vc.Size())&&(j>i-32768)&&(j>=0);j--){
			bool encontrado=false;
			loncont=0;				
			if(vc.Get(i)==vc.Get(j)){
				discont=i;
				for(int n=j;((vc.Get(n)==vc.Get(i))&&(loncont<258)&&(i<vc.Size())&&(!encontrado));n++){
						(vc.Get(n)!=vc.Get(i)&&loncont>258)?encontrado=true:i++,loncont++;
				}
				if(loncont>2){
					//cout<<"longitud : "<<loncont+254<<" distancia : "<<discont-j<<endl;
					vi.Add(loncont+254);
					vi.Add(discont-j);
				}
				else{
					i=discont;
				}
			}
		}	
		if(i<vc.Size())
			vi.Add(vc.Get(i));
	}

	vi.Add(256);
}


int LZ77::tamvc()const{
	return vc.Size();
}


unsigned int LZ77::CRC32()const{
	int n;
	int k;	
	unsigned long crc;
	unsigned long int tabla[256];
	char byte;
	for(n=0;n<256;n++){
   	 crc=(unsigned long)n;
   	 for(k=0;k<8;k++){
   	    (crc & 1)?crc=0xedb88320L ^ (crc>>1):crc=crc>>1;
       }
    	tabla[n]=crc;
	}
	crc=0xFFFFFFFF;
	for(int i=0;i<vc.Size();i++){
		byte=vc.Get(i);
		crc=(crc>>8) ^ tabla[(crc ^ byte)&0xFF];
	}
	crc=crc ^ 0xFFFFFFFF;
	return crc;
}


unsigned int LZ77::Get(int i)const{
	return vi.Get(i);
}


VD_unsignedchar LZ77::Getvc()const{
	return vc;
}


VD_unsignedint LZ77::Getvi()const{
	return vi;
}


LZ77 & LZ77::operator=(const LZ77 &l){
	if(this!=&l){
		vc=l.vc;
		vi=l.vi;
	}
	return *this;
}


istream & operator>>(istream &is,LZ77 &l){
	char c;
	while(is.get(c)){
		l.vc.Add(c);
	}
	return is;
}


ostream & operator<<(ostream &os, LZ77 &l){
	for(int i=0;i<l.vi.Size();i++){
		if(l.vi.Get(i)>258){
			os<<"("<<(l.vi.Get(i))<<","<<l.vi.Get(i+1)<<")";	
			i++;
		}
		else{
			(l.vi.Get(i)!=256)?os<<l.vi.Get(i):os<<" Fin Bloque:256";
		}
	}
	return os;
}
